<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>  interface 接口语法用法  </title>
</head>
<body></body></html>
<script>
    //于北京丰台  21-05-11夜 修订整理补充  
    //于         21-06-03-夜修订补充
    //于         21-08-08-午补充   
    //出现再别人的生活里要像一份礼物！ 

    // 什么是接口类型？ //接口interface？
    // 接口也是一种类型同理用来约束使用者   和number，string，boolean，enum这些数据类型一样，
    // 是一种描述对象||函数的东西(可以理解为形状) 
    /*      一个对象需要上面样的属性 
            函数需要什么参数或者返回什么样的值 
            数组应该是什么样子 
            一个类和继承类得符合什么样的描述 
       对象接口 函数接口 可索引接口 类接口 及接口的继承 定义混合类型...     
    */        

     
    //对象类型接口                      //类型检测器不会去检查属性的顺序，只要相应的属性存在并且类型也是对的即可 
            interface FullName{        //需求，要求定义一个函数输出一个人完整的名字，这个人的姓必须是字符串，名必须也是字符串 
                firstName: String;     
                lastName: string;
            }                           
            let obj = {
                firstName: "隔壁",
                lastName: "老王"        //如果不是string 会报错，比如lastName: 18
            }
                                        //{farstName,lastName} 使用了解构赋值   
            fucntion say({firstName,lastName}:FullName):void{
                console.log(`我叫:${farstName}+${lastName}`) 
            }
            say(obj)                    //我叫:隔壁+老王

        
//接口一般首字母大写 I 这是tslint要求的否则报错   *可以再tslint中关闭 在rules中添加如下规则 "interface-name":[true,"never-prefix"] 
//赋值的时候 变量的形状必须跟接口的形状保持一致  
//注意! 接口中可定义？ 
        //1可选属性 2只读属性 3任意属性 让接口更加的灵活
                     
        //定义接口 强约束 
            interface Istate {    
                name:String,
                age:number
            }
            var obj1:Istate;
            obj1 = {name:"张三",age:10}


        //1可选属性 存疑              //可选属性在给函数传入的参数对象中只有部分属性赋值了 常见 
            interface Istate2 {
                name: string,        //普通属性 设置需要存在的普通属性 
                age?: number,        //可选属性 存疑可有可无？  注意可选属性如果没有赋值 获取到的值是undefined 
                sex?: number,        //...
                studay?():void       //可选方法 存疑可有可无？  //对于可选的方法 必须先进行判断 再调用 否则报错 
            }         
            var obj2: Istate2;
            obj2 = {name:"张三",age:20}
            obj2 = {name:"马六"}    //这里赋值时 未给age也行  
            console.log(obj2.sex)   //可选属性未赋值 获取到的值为undefined 
            console.log(obj2.studay)//不可以这样调用 因为可能是未定义的对象  
                                    //正确的调用方法 
            if(obj2.studay){obj2.studay()}                               



        //2只读属性 (即默认情况下接口中定义的属性为可读可写的)
            interface Istate {
                name: string,
        readonly age: number        //只读属性 即定义初始值后 不想让它后续更改 在属性前面加上readonly关键字 
            }
            var obj4:Istate = {name:"赵四",age:10}
            obj4.name = "傻子"
            obj4.age = 20           //报错 因为上面已经为只读状态了readonly 
                        //只读数组类型 ReadonlyArray<T>类型 他与Array<T>相似，只是把所以可变属性方法去掉了，因此可确保数组创建后再也不能被修改 
                        let a: number[] = [1,2,3,4];
                        let or:ReadonlyArray<number> = a;
                        or[2] = 12; //error 
                        or.push(4)  //error
                        or.length = 100; //error 
                        
        //3任意类型         
                //属性个数不确定的时候 any必须是任意类型 
                //即后续我动态插入 添加的 
                interface Istate3 {
                        name:string|number,     //联合类型 这样的话 name可以是 字符串|数字
                        age?:number,            //存疑的一个age属性 给不给都可以 
                        [propName:string]:any   //后添加    还可以通过as或[propName: string]: any 来制定可以接受的其他额外属性
                }        
                var obj3:Istate3 = {name:"张三",age:10,sex:"男",isMarry:true}

        //接口继承 
              //接口夜是可以相互继承 这使得我们从一个接口里将成员复制到另一个接口里 
              //可以更灵活地将接口分割到可重用的模块中
              //一个接口可以继承多个接口，创建多个接口的继承接口 
               interface Shape{
                   color:color;
               }
               interface PenStorke {
                   penWidth:number;
               }
               interface all extends Shape,PenStorke{
                   allSize:number;
               }
               let all  = <all>{};
                all.color = "red";
                all.penWidth = 100;
                all.allSize = 5;





//接口中定义方法 
  //定义接口不仅仅可以有属性 也可以有方法  
  interface Ipersson {
      name: String;
      run(): void;
      eat(): void;
  }
  //如果我们有一个对象是该接口类型 那么必须包含对应的属性和方法 
  const p: Iperson = {
      name: "why",
      run(){
          console.log("这是一个方法")
      },
      eat(){
          console.log("这是一个方法too")
      }
  }




</script>